package turtle.system.invest;

public class IndexSeries {
	
	private int values[];
	private long sums[];
	private long sum2s[];
	
	private int mins[][];
	private int maxs[][];
	
	public IndexSeries(int values[]) {
		this.values = values.clone();
		sums = new long[values.length];
		sum2s = new long[values.length];
		
		sums[0] = values[0];
		sum2s[0] = values[0] * values[0];
		for (int i = 1, n = values.length; i < n; ++i) {
			long v = values[i];
			sums[i] = v + sums[i - 1];
			sum2s[i] = v * v + sum2s[i - 1];
		}
		
		int log2 = Util.integerLog2(values.length - 1) + 1, step = 1;
		mins = new int[log2][];
		maxs = new int[log2][];
		mins[0] = maxs[0] = values;
		for (int i = 1, n = values.length; i < log2; ++i) {
			int[] min = mins[i] = new int[n], lastmin = mins[i - 1];
			int[] max = maxs[i] = new int[n], lastmax = maxs[i - 1];
			for (int j = 0, b = n - step; j < b; ++j) {
				min[j] = Math.min(lastmin[j], lastmin[j + step]);
				max[j] = Math.max(lastmax[j], lastmax[j + step]);
			}
			for (int j = n - step; j < n; ++j) {
				min[j] = lastmin[j];
				max[j] = lastmin[j];
			}
			step += step;
		}
	}

	public int getValue(int index) {
		return values[index];
	}	
	
	public int getMaximum(int start, int length) {
		return getMaximum(start, length, Util.integerLog2(length));
	}

	public int getMaximum(int start, int length, int lengthLog2) {
		int a = maxs[lengthLog2][start];
		int b = maxs[lengthLog2][start + length - (1 << lengthLog2)]; 
		return a > b ? a : b;		
	}

	public int getMinimum(int start, int length) {
		return getMinimum(start, length, Util.integerLog2(length));
	}
	
	public int getMinimum(int start, int length, int lengthLog2) {
		int a = mins[lengthLog2][start];
		int b = mins[lengthLog2][start + length - (1 << lengthLog2)]; 
		return a < b ? a : b;		
	}
	
	public double getAverage(int start, int length) {
		long initial = start > 0 ? sums[start - 1] : 0;
		return (double) (sums[start + length - 1] - initial) / length;
	}

    public int size() {
        return values.length;
    }
}
